package system.task.listener;

import framework.runtime.SystemContext;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Trigger;
import org.quartz.TriggerListener;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import system.entity.SysTaskJob;
import system.service.sys.SysTaskJobService;
import system.task.utils.TaskUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
public class TrigListener implements TriggerListener {
    @Override
    public String getName() {
        return this.getClass().getName();
    }

    private void logMisfires(Trigger trigger, List<Date> missedFireTimes) {
        String triggerKey = trigger.getKey().toString();
        String jobKey = trigger.getJobKey().toString();

        System.out.printf("Trigger %s (Job %s) 有以下 Misfire 时间点:\n", triggerKey, jobKey);
        missedFireTimes.forEach(time ->
                System.out.println(" - " + time)
        );

        // 存储到数据库：
        // missedFireTimes.forEach(time ->
        //     misfireRepository.save(new MisfireRecord(triggerKey, time))
        // );
    }

    private List<Date> calculateMissedFireTimes(Trigger trigger, Date startTime, Date endTime) {
        List<Date> missedTimes = new ArrayList<>();
        Date theoreticalTime = startTime;

        // 遍历从上次触发时间到当前时间的所有理论触发点
        while (theoreticalTime != null && theoreticalTime.before(endTime)) {
            missedTimes.add(theoreticalTime);
            theoreticalTime = trigger.getFireTimeAfter(theoreticalTime);
        }

        // 移除最后一次实际触发时间（因为它是成功的，不是 Misfire）
        if (!missedTimes.isEmpty()) {
            missedTimes.remove(missedTimes.size() - 1);
        }

        return missedTimes;
    }

    private void checkMissedFirings(Trigger trigger) {
        Date now = new Date();
        Date previousFireTime = trigger.getPreviousFireTime();
        // Date nextFireTime = trigger.getNextFireTime();

        if (previousFireTime == null) {
            // 首次触发无历史记录
            return;
        }

        // 忽略本次执行
        Date nextTime = trigger.getFireTimeAfter(previousFireTime);

        // 计算所有遗漏的触发时间
        List<Date> missedFireTimes = calculateMissedFireTimes(trigger, nextTime, now);

        // 记录或处理 Misfire 时间点
        logMisfires(trigger, missedFireTimes);
    }

    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
        // 触发时执行
    }

    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
        JobKey jobKey = trigger.getJobKey();

        // 是否允许触发
        boolean canceled = false;

        //
        SysTaskJobService jobService = SystemContext.getBean(SysTaskJobService.class);
        SysTaskJob query = new SysTaskJob();
        query.setName(jobKey.getName());
        SysTaskJob job = jobService.first(query);
        if (job == null) {
            log.warn("execute job but job deleted " + jobKey.getName() + " in database, skip once.");
            // 取消
            canceled = true;
            return canceled;
            //throw new JobExecutionException("execute job but job deleted " + jobKey.getName() + " in database");
        }

        //
        Environment environment = SystemContext.getBean(Environment.class);
        String[] activeProfiles = environment.getActiveProfiles();
        if (activeProfiles.length == 0) {
            activeProfiles = new String[]{
                    "default"
            };
        }
        String hostname = TaskUtil.hostname();

        //
        jobExecutionContext.put(TaskUtil.TASK_TASK_JOB_NAME, job);
        jobExecutionContext.put(TaskUtil.TASK_TASK_RUN_ENV, String.join(",", activeProfiles));
        jobExecutionContext.put(TaskUtil.TASK_TASK_RUN_HOST, hostname);

        // is manual
        if ("1".equals(jobExecutionContext.getTrigger().getJobDataMap().get(TaskUtil.TASK_TRIGGER_MANUAL))) {
            // 手动，允许执行，不取消
            canceled = false;
            return canceled;
        }

        //
        if (StringUtils.hasText(job.getEnvName()) && !"-".equals(job.getEnvName())) {
            String envName = job.getEnvName().trim();
            boolean include = false;
            if (activeProfiles != null) {
                for (String activeProfile : activeProfiles) {
                    if (envName.equals(activeProfile)) {
                        include = true;
                        break;
                    }
                }
            }
            if (!include) {
                log.info("Job " + jobKey.getName() + " require run in " + envName + " ,not in the profiles " + String.join(",", activeProfiles) + ", skip once.");
                canceled = true;
                return canceled;
            }
        }

        //
        if (StringUtils.hasText(job.getHostname()) && !"-".equals(job.getHostname())) {
            if (StringUtils.hasText(hostname)) {
                if (!hostname.equals(job.getHostname().trim())) {
                    log.info("Job " + jobKey.getName() + " require run on host " + job.getHostname() + " , the host " + hostname + " , skip once.");
                    canceled = true;
                    return canceled;
                }
            }
        }

        //
        return canceled;
    }

    @Override
    public void triggerMisfired(Trigger trigger) {
        // 检查遗漏的 Misfire
        // checkMissedFirings(trigger);
    }

    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
        // 触发完成时执行
    }
}
